package Simcomp::Admin;
use strict;
use warnings;
use lib qw( ../ );
use Simcomp::Disk;
use Simcomp::CPU;
use Simcomp::Process;
use Simcomp::Random;
use Simcomp::FileLoader;

our $VERSION = "0.01";

sub new
{
    my $class = shift;
    my %attrib;
    bless \%attrib, $class;
    my $self = \%attrib;
    $self->create_objects;
    $self->generate_process_list;
    return $self;
}

sub get_config
{
    return Simcomp::FileLoader::load_config;
}

sub generate_process_list
{
    my $self = shift;
    my $time_sub = Simcomp::Random::getDistribution( $self->{'time_info'}->{'type'} );
    my $time_spent = 0;
    my @process_list;
    while ( $time_spent <= 100 )
    {
	my $process = Simcomp::Process->new();
	$time_spent += &$time_sub( @{$self->{'time_info'}->{'params'}} );
	$process->set_start_time( $time_spent );
	push @process_list, $process;
    }
    
    $self->{'p_list'} = \@process_list;
}

sub next_event_dev
{
    my $self = shift;
    my $cpu = $self->{'cpu'};
    my $diskA = $self->{'diskA'};
    my $diskB = $self->{'diskB'};
    
    my $dev_chosen = undef;
    for my $dev ( $self, $cpu, $diskA, $diskB )
    {
	$dev_chosen = $dev if ( defined ($dev->event_time) and 
				( !defined ($dev_chosen) or $dev->event_time < $dev_chosen->event_time ) );
	
    }
    
    return $dev_chosen;


}

sub main_loop
{
    my $self = shift;
    my $current_time = 0;
    
    while ( $current_time <= 100 )
    {
	my $dev_chosen = $self->next_event_dev;
	next unless defined $dev_chosen;
	$current_time = $dev_chosen->event_time;
	if ( $current_time <= 100 )
	{
	    for my $dev ( $self, $self->{'cpu'}, $self->{'diskA'}, $self->{'diskB'} )
	    {
		$dev->set_current_time ( $current_time );
		$dev->feed_result() unless ($dev == $self);
	    }
	   
	    $dev_chosen->act;

	}
	
    }
}

sub print_statistics
{
    my $self = shift;
    my $result = $self->{'result'};
    
    my %st = $result->get_statistics;
    
    
    printf  "%-50s%15.6f\n" x 7,
    "Média de tempo total por processo:", $st{'total_time'},
    "Tempo médio na fila de CPU:", $st{'time_in_cpu_queue'},
    "Tempo médio na fila do Disco A:", $st{'time_in_disk_A_queue'},
    "Tempo médio na fila do Disco B:", $st{'time_in_disk_B_queue'},
    "Tamanho médio da fila de CPU:", $st{'cpu_media_queue_size'},
    "Tamanho médio da fila no Disco A:", $st{'diskA_media_queue_size'},
    "Tamanho médio da fila do Disco B:", $st{'diskB_media_queue_size'};
    printf "%-50s%14.6f\n" x 5,
    "Porcentagem de tempo com CPU processando:", $st{'cpu_processing_percentage'},
    "Porcentagem de tempo com CPU em overhead:", $st{'cpu_overhead_percentage'},
    "Porcentagem de tempo ocioso da CPU:", $st{'cpu_idle_percentage'},
    "Porcentagem de tempo ocioso do Disco A:", $st{'diskA_idle_percentage'},
    "Porcentagem de tempo Disco do Disco B:", $st{'diskB_idle_percentage'};
						
}

sub event_time
{
    my $self = shift;
    my @p_list = @{$self->{'p_list'}};
    
    return ($p_list[0])->{'start_time'};
}

sub act
{
    my $self = shift;
    my $process = shift @{$self->{'p_list'}};
    $self->{'cpu'}->receive_process( $process );
}

sub create_objects
{
    my $self = shift;
    my %config = $self->get_config;

    $self->{'result'} = Simcomp::Result->new();
    
    $self->{'diskA'} = Simcomp::Disk->new( name => 'DISK_A',
					   result => $self->{'result'},
					   dist_info => $config{'tda'} );
    
    $self->{'diskB'} = Simcomp::Disk->new ( name => 'DISK_B',
					    result => $self->{'result'},
					    dist_info => $config{'tdb'} );

    $self->{'cpu'} = Simcomp::CPU->new( result => $self->{'result'},
					overhead => $config{'tover'},
					process_time => $config{'tms'},
					quantum => $config{'tqt'},
					disk_A => $self->{'diskA'},
					disk_B => $self->{'diskB'} );
    
    $self->{'time_info'} = $config{'tec'};

}

sub do_simulation
{
    my $self = shift;
    $self->main_loop;
    $self->print_statistics;
}

sub set_current_time
{
    $_[0]->{'current_time'} = $_[1];
}


1;
